package middleware

import (
	"strings"

	"gitee.com/huangxinbo/xcas/pkg/response"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
)

// ErrorMiddleware global error handling middleware
func (m *Middleware) ErrorMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		// Execute error handling after request processing is completed
		c.Next()

		// Check if there are any errors
		if len(c.Errors) > 0 {
			// Get the last error for processing
			lastErr := c.Errors.Last()
			if lastErr != nil {
				m.handleError(c, lastErr.Err)
			}
			return
		}
	}
}

// handleError handles different types of errors
func (m *Middleware) handleError(c *gin.Context, err error) {
	// Log error
	m.Logger.Error("Request error",
		zap.String("method", c.Request.Method),
		zap.String("path", c.Request.URL.Path),
		zap.String("client_ip", c.ClientIP()),
		zap.Error(err),
	)

	// Return corresponding error response based on error type
	switch {
	case isBindError(err):
		// Parameter binding error - return 400 status code
		response.Error[any](c, response.INVALID_PARAMS, m.I18n.T("Invalid request parameters"), nil)
	case isValidationError(err):
		// Data validation error - return 400 status code
		response.Error[any](c, response.INVALID_PARAMS, m.I18n.T("Data validation failed"), nil)
	case isDatabaseError(err):
		// Database error - return 500 status code
		response.Error[any](c, response.DATABASE_ERROR, m.I18n.T("Database operation error"), nil)
	case isNotFoundError(err):
		// Resource not found error - return 404 status code
		response.Error[any](c, response.NOT_FOUND, m.I18n.T("Requested resource not found"), nil)
	case isUnauthorizedError(err):
		// Unauthorized error - return 401 status code
		response.Error[any](c, response.UNAUTHORIZED, m.I18n.T("Unauthorized access"), nil)
	case isForbiddenError(err):
		// Access forbidden error - return 403 status code
		response.Error[any](c, response.FORBIDDEN, m.I18n.T("Access forbidden"), nil)
	default:
		// Default system error - return 500 status code
		response.Error[any](c, response.ERROR, m.I18n.T("Internal server error"), nil)
	}
}

// Error type judgment helper functions
func isBindError(err error) bool {
	// Determine if it's a parameter binding error
	return strings.Contains(strings.ToLower(err.Error()), "bind") ||
		strings.Contains(strings.ToLower(err.Error()), "json") ||
		strings.Contains(strings.ToLower(err.Error()), "unmarshal")
}

func isValidationError(err error) bool {
	// Here you can judge based on specific validation library error types
	// For example, using go-playground/validator, etc.
	return strings.Contains(strings.ToLower(err.Error()), "validation") ||
		strings.Contains(strings.ToLower(err.Error()), "validate")
}

func isDatabaseError(err error) bool {
	// Determine if it's a database-related error
	return strings.Contains(strings.ToLower(err.Error()), "database") ||
		strings.Contains(strings.ToLower(err.Error()), "sql") ||
		strings.Contains(strings.ToLower(err.Error()), "duplicate") ||
		strings.Contains(strings.ToLower(err.Error()), "constraint")
}

func isNotFoundError(err error) bool {
	// Determine if it's a resource not found error
	return strings.Contains(strings.ToLower(err.Error()), "not found") ||
		strings.Contains(strings.ToLower(err.Error()), "no rows") ||
		strings.Contains(strings.ToLower(err.Error()), "record not found")
}

func isUnauthorizedError(err error) bool {
	// Determine if it's an unauthorized error
	return strings.Contains(strings.ToLower(err.Error()), "unauthorized") ||
		strings.Contains(strings.ToLower(err.Error()), "auth") ||
		strings.Contains(strings.ToLower(err.Error()), "token")
}

func isForbiddenError(err error) bool {
	// Determine if it's an access forbidden error
	return strings.Contains(strings.ToLower(err.Error()), "forbidden") ||
		strings.Contains(strings.ToLower(err.Error()), "permission")
}
